package com.binarysoft.service.type;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import common.framework.dsb.AbstractServiceBean;
import common.framework.dsb.annotation.DSBLog;
import common.framework.dsb.annotation.DSBService;
import common.framework.dsb.service.ServiceContext;
import common.framework.log.Logger;

/**
 * @author David Yuan
 * 
 */
@DSBService(name = "DSB/TypeService", startup = true)
public class TypeServiceBean extends AbstractServiceBean implements TypeService {

	private TypeDAO dao = null;

	private Map<String, Type> typeMap = new HashMap<String, Type>();

	/*
	 * 
	 * 
	 * @see
	 * common.framework.dsb.AbstractServiceBean#start(common.framework.dsb.server
	 * .ServiceContext)
	 */
	@Override
	@DSBLog(log = "console")
	public void start(ServiceContext arg0) throws Exception {
		super.start(arg0);
		dao = new TypeMysqlDAO();
		loadData();
	}

	public void refresh() throws Exception {
		typeMap.clear();
		loadData();
	}

	@Override
	public void close() throws Exception {
		typeMap.clear();
	}

	@Override
	public boolean isatype(String typeA, String typeB) {
		if (typeB.equalsIgnoreCase(typeA)) {
			return true;
		}
		Collection<Type> allSubTypes = getAllSubTypes(typeB);
		for (Type t : allSubTypes) {
			if (t.getID().equalsIgnoreCase(typeA)) {
				return true;
			}
		}
		return false;
	}

	@Override
	public boolean isLinealFamily(String typeA, String typeB) {
		if (typeA.equalsIgnoreCase(typeB)) {
			return true;
		}
		return isatype(typeA, typeB) || isatype(typeB, typeA);
	}

	@DSBLog(log = "console")
	@Override
	public void addType(String typeID, String typeName, String typeDesc, String parentTypeID) throws Exception {
		if (typeID == null) {
			throw new Exception("type ID can not be null.");
		}
		if (parentTypeID == null || "".equalsIgnoreCase(parentTypeID.trim())) {
			throw new Exception("parent type ID can not be null.");
		}
		Type type = new Type();
		type.setID(typeID);
		type.setName(typeName);
		type.setDescription(typeDesc);
		type.setParentID(parentTypeID);
		dao.addType(typeID, typeName, typeDesc, parentTypeID);
		typeMap.put(typeID, type);
	}

	@DSBLog(log = "console")
	@Override
	public void addType(Type type) throws Exception {
		if (type.getID() == null) {
			throw new Exception("typeID can not be null.");
		}
		String parentTypeID = type.getParentID();
		if (parentTypeID == null || "".equalsIgnoreCase(parentTypeID.trim())) {
			throw new Exception("parent type ID can not be null.");
		}
		dao.addType(type.getID(), type.getName(), type.getDescription(), type.getParentID());
		typeMap.put(type.getID(), type);
	}

	@DSBLog(log = "console")
	@Override
	public void deleteType(String typeID) throws Exception {
		if (typeID != null) {
			Collection<Type> allSubTypes = this.getAllSubTypes(typeID);
			Collection<String> typeIDs = new ArrayList<String>();
			for (Type type : allSubTypes) {
				typeIDs.add(type.getID());
			}
			typeIDs.add(typeID);
			dao.deleteType(typeIDs);
			for (String t : typeIDs) {
				typeMap.remove(t);
			}
		}
	}

	@DSBLog(log = "console")
	@Override
	public void updateType(String typeID, String typeName, String typeDesc, String parentTypeID) throws Exception {
		dao.updateType(typeID, typeName, typeDesc, parentTypeID);
		Type type = getType(typeID);
		if (type != null) {
			type.setName(typeName);
			type.setDescription(typeDesc);
			type.setParentID(parentTypeID);
		}
	}

	@DSBLog(log = "console")
	@Override
	public boolean exists(String typeID) {
		if (typeID != null) {
			typeID = typeID.toLowerCase();
			return typeMap.containsKey(typeID);
		}
		return false;
	}

	@DSBLog(log = "console")
	@Override
	public Type getType(String typeID) throws Exception {
		if (typeID != null) {
			return typeMap.get(typeID);
		}
		return null;
	}

	@DSBLog(log = "console")
	@Override
	public Type getParentType(String typeID) throws Exception {
		if (typeID != null) {
			Type myType = typeMap.get(typeID);
			if (myType != null) {
				String parentID = myType.getParentID();
				if (parentID != null) {
					return typeMap.get(parentID);
				}
			}
		}
		return null;
	}

	@DSBLog(log = "console")
	@Override
	public Collection<Type> getSubTypes(String typeID) {
		Collection<Type> childs = new ArrayList<Type>();
		if (typeID != null) {
			for (Type t : typeMap.values()) {
				if (typeID.equalsIgnoreCase(t.getParentID())) {
					childs.add(t);
				}
			}
		}
		return childs;
	}

	@DSBLog(log = "console")
	@Override
	public Collection<Type> getAllSubTypes(String typeID) {
		Collection<Type> childs = new ArrayList<Type>();
		searchAllSubTypes(typeID, childs);
		return childs;
	}

	private void searchAllSubTypes(String typeID, Collection<Type> childs) {
		if (typeID != null) {
			for (Type t : typeMap.values()) {
				if (t.getParentID() == null || "".equalsIgnoreCase(t.getParentID().trim())) {
					continue;
				}
				if (t.getParentID().trim().equalsIgnoreCase(typeID)) {
					childs.add(t);
					searchAllSubTypes(t.getID(), childs);
				}
			}
		}
	}

	private void loadData() throws Exception {
		try {
			typeMap.clear();
			typeMap.putAll(dao.loadAllTypes());
		} catch (Exception e) {
			Logger.printStackTrace(Logger.FATAL_LEVEL, "error initialization type service", e);
			throw e;
		}
	}
}
